/*
 * JZebraApplet.java
 *
 * Created on July 28, 2008, 11:15 AM
 */
package jzebra;

import java.awt.Component;
import java.util.HashSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.print.PrintException;
import javax.print.PrintService;
import javax.swing.UIManager;

/**
 * Web applet, displayed as a Print button.
 * @author  A. Tres Finocchiaro
 */
public class JZebraApplet extends javax.swing.JApplet implements Paramable {
    private PrintService ps;
    private ConfigLoader cl;


    private PrintRaw pr;

    boolean printFailed = false;
    boolean showMessages = false;
    boolean showIcon = true;
    boolean autoPrint;
    private String errorMessage;
    private String successMessage;
    private String messageTitle;

    /**
     * Returns 'true' if an exception was thrown in the printing process
     * @return
     */
    public boolean printFailed() {
        return printFailed;
    }

    /**
     * Perform PrintRaw.print() and handles the output of exceptions and
     * debugging
     */
    private void print() {
        Exception e = JZebraTools.doPrint(this, pr, cl);
        if (showMessages) {
            if (e == null) {
                JZebraTools.showMessage(this, successMessage);
            }
            else {
                JZebraTools.showMessage(this, errorMessage, e);
            }
        }
    }

    /** Initializes the applet JZebraApplet */
    @Override
    public void init() {
        try {
            java.awt.EventQueue.invokeAndWait(new Runnable() {
                public void run() {
                    cl = new ConfigLoader();
                    pr = new PrintRaw();
                    
                    setLookAndFeel();

                    // Initialize our GUI components
                    initComponents();
                    
                    JZebraTools.processParameters(JZebraApplet.this, pr, cl);
                    HashSet<String> varNames = JZebraTools.hashVars(cl.getRawCmds());
                    
                    pr.setPrintService(ps);
                    pr.setRawCmds(JZebraTools.replaceWildCards(JZebraApplet.this, varNames, cl.getRawCmds()));
                    if (autoPrint) {
                        printButton.doClick();
                    }
                    
                    
                }
            });
        } catch (Exception e) {
            JZebraTools.log(e);
        }
    }

    @Override
    public void destroy() {
        this.stop();
        super.destroy();
    }

    /** This method is called from within the init() method to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        printButton = new javax.swing.JButton();

        setName("Form"); // NOI18N

        javax.swing.ActionMap actionMap = org.jdesktop.application.Application.getInstance(jzebra.JZebraApp.class).getContext().getActionMap(JZebraApplet.class, this);
        printButton.setAction(actionMap.get("printCard")); // NOI18N
        org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(jzebra.JZebraApp.class).getContext().getResourceMap(JZebraApplet.class);
        printButton.setIcon(resourceMap.getIcon("printButton.icon")); // NOI18N
        printButton.setText(resourceMap.getString("printButton.text")); // NOI18N
        printButton.setName("printButton"); // NOI18N
        printButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                printButtonActionPerformed(evt);
            }
        });

        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(printButton)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(printButton)
        );
    }// </editor-fold>//GEN-END:initComponents

    private void printButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_printButtonActionPerformed
        print();
    }//GEN-LAST:event_printButtonActionPerformed

    /**
     * Sets the button to look like your OS
     */
    private void setLookAndFeel() {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (Exception e) {
            JZebraTools.log(Level.WARNING, "Error setting L&F.", e);
        }
    }

    /*private void processParameters() {
        // Cycle through parameters and load those applicable to a web applet
       
        
        for (ParameterLoader pl : ParameterLoader.values()) {
            try {
                pl.setParameter(this);
            }
            catch (PrintException e) {
                String msg = "Error setting " +
                    pl.toString() + "(" + pl.getEnumType().toString() +
                    ") parameter while loading applet. " +
                    "Printing functionality will fail.";
                if (showMessages) {
                    JZebraTools.showMessage(this, msg, e);
                }
                else {
                    JZebraTools.log(this, msg, e);
                }
            }
        }
        
        // Read file contents to buffer
        try {
            cl.readFile();
        } catch (IOException e) {
            String msg = "Error reading \"" + cl.getConfigPath() + "\"" + " (" +
                    cl.getConfigType().toString() + ")";
            
        } finally {
            cl.closeStreams();
        }

        pr.setPrintService(ps);
        pr.setRawCmds(parseVariables(cl.getRawCmds()));
    }*/


    /**
     * Replaces wildcard variables, like $FIRSTNAME$ with the variable supplied
     * in the web applet: param name="FIRSTNAME" value="Tres"
     * @param configCmds
     * @return
     */
    /*private String parseVariables(String configCmds) {
        String parsedCmds = new String(configCmds);

        HashSet<String> varNames = new HashSet<String>();
        Pattern p = Pattern.compile("\\$(\\w+)");
        Matcher m = p.matcher(configCmds);
        while (m.find()) {
            varNames.add(m.group(1));
        }

        for (String s : varNames) {
            if (!isBlank(getParameter(s))) {
                parsedCmds = parsedCmds.replaceAll("\\$" + s, getParameter(s));
                
            }
            else {
                Logger.getLogger(this.getClass().getName()).log(
                        Level.WARNING, "Applet <param name=\"" + s + "\" ...> " +
                        "not specified in html applet code. Leaving verbatim in" +
                        "raw cmds.");
            }
        }
        return parsedCmds;
    }*/

    /**
     * Returns true if given String is empty or null
     * @param s
     * @return
     */
    private boolean isBlank(String s) {
        return s == null || s.trim().equals("");
    }
    
    /**
     * Retrieves the error message after an applet loading failure or print 
     * failure
     * @return
     */
    public String getErrorMessage() {
        return errorMessage;
    }

    /**
     * Overrides getParameter() to allow all upper or all lowercase parameter names
     * @param name
     * @return
     */
    @Override
    public String getParameter(String name) {
        if (name != null) {
            String retVal = super.getParameter(name);
            return isBlank(retVal) ? super.getParameter(name.toUpperCase()) : retVal;
        }
        return super.getParameter(name);
    }
    
    /**
     * Sets the message displayed when a print error has occured.  This can be
     * an empty config, unknown printer name, etc.  Default is "jZebra encountered
     * an error...".
     * <p>This message supports &lt;html&gt; tags.  See included 
     * <strong>preview-application.html</strong> for more details.</p>
     * @param successMessage
     */
    public boolean setErrorMessage(String errorMessage) {
        this.errorMessage = errorMessage;
        return errorMessage != null;
    }
    
    public boolean setErrorMessage(String errorMessage, String defaultMessage) {
        return setErrorMessage(errorMessage) ? true: setErrorMessage(defaultMessage);
    }

    /**
     * Retrieves the success message after a successfull print.
     * @return
     */
    public String getSuccessMessage() {
        return successMessage;
    }

    /**
     * Sets the message displayed when raw data has been successfully sent to
     * the printer.  Default is "jZebra successfully sent...".
     * <p>This message supports &lt;html&gt; tags.  See included 
     * <strong>preview-application.html</strong> for more details.</p>
     * @param successMessage
     */
    public boolean setSuccessMessage(String successMessage) {
        this.successMessage = successMessage;
        return successMessage != null;
    }
    
    public boolean setSuccessMessage(String successMessage, String defaultMessage) {
        return setSuccessMessage(successMessage) ? true: setSuccessMessage(defaultMessage);
    }
    
    /**
     * Retreives the title of the message dialog, which can be specified in the
     * applet parameters in html.  Default is "jZebra".
     * @return
     */
    public String getMessageTitle() {
        return messageTitle;
    }

    /**
     * Sets the title of the message dialogs to the given string, usually
     * supplied in the applet parameters. Default is "jZebra".
     * @param messageTitle
     */
    public boolean setMessageTitle(String messageTitle) {
        this.messageTitle = messageTitle;
        return messageTitle != null;
    }
    
    public boolean setMessageTitle(String messageTitle, String defaultTitle) {
        return setMessageTitle(messageTitle) ? true: setMessageTitle(defaultTitle);
    }
    
    
    /**
     * Returns true if applet is set automatically print upon loading
     * Default is true
     * @param autoPrint
     */
    public boolean isAutoPrint() {
        return autoPrint;
    }

    /**
     * Sets applet to print automatically on load, normally specified by
     * applet parameter in html.  Default is true
     * @param autoPrint
     */
    public boolean setAutoPrint(boolean autoPrint) {
        this.autoPrint = autoPrint;
        return true;
    }

    public boolean setAutoPrint(String autoPrint) {
        if (autoPrint != null) {
            this.autoPrint = autoPrint.equalsIgnoreCase("true");
        }
        return autoPrint != null;
    }

    public boolean setAutoPrint(String autoPrint, String defaultPrint) {
        return setAutoPrint(autoPrint) ? true : setAutoPrint(defaultPrint);
    }

    public boolean setButtonText(String buttonText) {
        printButton.setText(buttonText);
        return buttonText != null;
    }

    public boolean setButtonText(String buttonText, String defaultText) {
        return setButtonText(buttonText) ? true: setButtonText(defaultText);
    }

    /**
     * Returns the exception thrown during applet loading and printing.  Returns
     * null if none is set.
     * @return
     */
    //public Exception getException() {
    //    return ex;
    //}

    /**
     * Creates the print service by iterating through printers until finding
     * matching printer containing "printerName" in its description
     * @param printerName
     * @return
     */
    public boolean setPrinterName(String printerName) {
        return ((ps = PrintServiceMatcher.findPrinter(printerName)) != null);
    }

    public boolean setPrinterName(String printerName, String defaultPrinter) {
        return setPrinterName(printerName) ? true : setPrinterName(defaultPrinter);
    }
            
    public String getPrinterName() {
        if (ps != null) {
            return ps.getName();
        }
        return null;
    }
    
    /**
     * Returns true if applet is set to display status message in a message box
     * Default is false.
     * @return
     */
    public boolean isMessagesShown() {
        return showMessages;
    }

    /**
     * Sets applet to show messages in a message box, normally specified by
     * applet parameter in html.  Default is false.
     * @param showMessages
     */
    public boolean setMessagesShown(boolean showMessages) {
        this.showMessages = showMessages;
        return true;
    }
    
    public boolean setMessagesShown(String showMessages) {
        if (showMessages != null) {
            return setMessagesShown(showMessages.equalsIgnoreCase("true"));
        }
        return false;
    }

    public boolean setMessagesShown(String showMessages, String defaultMessages) {
        return setMessagesShown(showMessages) ? true: setMessagesShown(defaultMessages);
    }
    
        
    /**
     * Returns the PrintRaw object associated with this applet, if any.  Returns
     * null if none is set.
     * @return
     */
    public PrintRaw getPrintRaw() {
        return pr;
    }
    

    /**
     * Returns the PrintService object associated with this applet, if any.  Returns
     * null if none is set.
     * @return
     */
    public PrintService getPrintService() {
        return ps;
    }

    public ConfigLoader getConfigLoader() {
        return cl;
    }
    
    public boolean setIconShown(boolean showIcon) {
        this.showIcon = showIcon;
        if (!showIcon) {
            printButton.setIcon(null);
        }
        return true;
    }
    
    public boolean setIconShown(String showIcon) {
        if (showIcon != null) {
            return setIconShown(showIcon.equalsIgnoreCase("true"));
        }
        return false;
    }

    public boolean setIconShown(String showIcon, String showDefault) {
        return setIconShown(showIcon) ? true: setIconShown(showDefault);
    }
    
    public boolean isIconShown() {
        return showIcon;
    }
    
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton printButton;
    // End of variables declaration//GEN-END:variables

    public String getButtonText() {
        return printButton.getText();
    }

    public Component getComponent() {
        return this.getRootPane();
    }

    
    
}
